package com.gitee.wsl.platform

import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.UnsafeNumber
import kotlinx.cinterop.useContents
import platform.CoreFoundation.kCFBundleNameKey
import platform.Foundation.NSBundle
import platform.Foundation.NSOperationQueue
import platform.Foundation.NSProcessInfo
import kotlin.experimental.ExperimentalNativeApi
import kotlin.native.Platform
import platform.Foundation.NSThread
import platform.darwin.TARGET_OS_SIMULATOR



@OptIn(ExperimentalNativeApi::class)
internal object ApplePlatform {

    val lineSeparator: String = "\n"

    val fileSeparator: String = "/"

    private val processInfo = NSProcessInfo.processInfo

    // processInfo.operatingSystemName() returns only "NSMACHOperatingSystem", no matter if being called for
    // macOS, iOS, ..., so we cannot rely on it
    val osName: String = Platform.osFamily.name

    val osVersion: String = processInfo.operatingSystemVersionString

    val cpuArchitecture: String? = Platform.cpuArchitecture.name.lowercase()


    val userName = processInfo.environment["USER"]

    val logName = processInfo.environment["LOGNAME"]

    val userHome = processInfo.environment["HOME"]

//    val isRunningInDebugMode: Boolean =
//        NativeDefaults.isRunningInDebugMode

    fun getEnvironmentVariables(): Map<String, String> =
        NSProcessInfo.processInfo.environment.entries.associateBy({ it.key.toString() }, { it.value.toString() })

    fun getCurrentThreadName(): String? {
        val currentThread = NSThread.currentThread

        return currentThread.name?.takeIf { it.isNotBlank() }
            ?: currentThread.description
            ?: NSOperationQueue.currentQueue?.underlyingQueue?.description
    }

    fun printStackTrace() {
        NSThread.callStackSymbols
            .drop(1) // skip invocation of Exception constructor and this method
            .forEach { callStackSymbol ->
                println(callStackSymbol)
            }
    }

    @OptIn(ExperimentalForeignApi::class)
    val appName: String? by lazy {
//      val info = NSBundle.mainBundle.infoDictionary!!
//      println("appName: ${info["CFBundleName"]}, displayName: ${info["CFBundleDisplayName"]}, identifier: ${info["CFBundleIdentifier"]}, appBuild: ${info["CFBundleVersion"]}, appVersion: ${info["CFBundleShortVersionString"]}")
        NSBundle.mainBundle.infoDictionary?.get(kCFBundleNameKey) as? String
    }


    @OptIn( ExperimentalForeignApi::class)
    private fun isOsLogSupported(): Boolean {
        val osVersion = NSProcessInfo.processInfo.operatingSystemVersion

        return osVersion.useContents {
            val majorVersion = this.majorVersion.toInt()

            // os_log is available for: iOS 10.0+, iPadOS 10.0+, macOS 10.12+, Mac Catalyst 13.1+, tvOS 10.0+, watchOS 3.0+ (https://developer.apple.com/documentation/os/1643744-os_log_create)
            when (Platform.osFamily) {
                OsFamily.MACOSX -> majorVersion > 10 || (majorVersion == 10 && this.minorVersion >= 12)
                OsFamily.IOS, OsFamily.TVOS -> majorVersion >= 10
                OsFamily.WATCHOS -> majorVersion >= 3
                else -> false
            }
        }
    }

}


@OptIn(ExperimentalNativeApi::class)
 fun platform(): PlatformType {
    val nativePlatform = Platform

    val arch = nativePlatform.cpuArchitecture.asArch()
    val version = NSProcessInfo.processInfo.operatingSystemVersionString

    val isSimulator = TARGET_OS_SIMULATOR != 0

    return when (nativePlatform.osFamily) {
        OsFamily.MACOSX -> PlatformType.OS.Desktop.MacOs(arch, version)
        OsFamily.IOS -> PlatformType.OS.IOS(arch, version, isSimulator)
        OsFamily.TVOS -> PlatformType.OS.TvOs(arch, version, isSimulator)
        OsFamily.WATCHOS -> PlatformType.OS.WatchOs(arch, version, isSimulator)
        else -> PlatformType.OS.Unknown(arch, version)
    }
}